/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*
* Copyright 2006 - 2013 Pentaho Corporation. All rights reserved.
*/
package org.pentaho.platform.engine.security;
/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright 2011 Pentaho Corporation. All rights reserved.
*
* @created June 2011
* @author mbatchelor
*/
import org.apache.commons.codec.binary.Base64;
import org.pentaho.platform.api.engine.ObjectFactoryException;
import org.pentaho.platform.api.util.IPasswordService;
import org.pentaho.platform.api.util.PasswordServiceException;
import org.pentaho.platform.util.messages.LocaleHelper;
import org.springframework.beans.factory.InitializingBean;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.spec.AlgorithmParameterSpec;
public class CipherEncryptionService implements IPasswordService, InitializingBean {
private String saltString = "_CyPh3r_";
private String algorithm = "PBEWithMD5AndDES";
private String encryptionKey = "P3ntah0C1ph3r";
private final int saltLength = 8; // Eight Byte Cipher Salt
private int iterations = 19;
public void setSalt( String value ) {
this.saltString = value;
}
public String getSalt() {
return this.saltString;
}
public void setAlgorithm( String value ) {
this.algorithm = value;
}
public String getAlgorithm() {
return this.algorithm;
}
public void setEncryptionKey( String value ) {
this.encryptionKey = value;
}
public String getEncryptionKey() {
return this.encryptionKey;
}
public void setIterations( int value ) {
this.iterations = value;
}
public int getIterations() {
return this.iterations;
}
private AlgorithmParameterSpec paramSpec;
private SecretKey secretKey;
public void afterPropertiesSet() throws ObjectFactoryException {
if ( ( saltString == null ) || ( algorithm == null ) || ( encryptionKey == null ) ) {
throw new ObjectFactoryException( "Required properties not set - need Salt, algorithm and encryption key" );
}
if ( saltString.length() != this.saltLength ) {
// Make sure that the salt length is 8 bytes - the PBEParameterSpec doesn't anything but
if ( saltString.length() < saltLength ) {
saltString = ( saltString + "!@#$%^&*" ).substring( 0, saltLength ); // postfix bytes to pad it out
} else if ( saltString.length() > saltLength ) {
saltString = saltString.substring( 0, saltLength ); // Trim off longer than 8-bytes
}
}
byte[] saltBytes = saltString.getBytes();
paramSpec = new PBEParameterSpec( saltBytes, getIterations() );
PBEKeySpec skeySpec = new PBEKeySpec( getEncryptionKey().toCharArray(), saltBytes, getIterations() );
try {
secretKey = SecretKeyFactory.getInstance( getAlgorithm() ).generateSecret( skeySpec );
} catch ( Exception ex ) {
ex.printStackTrace();
throw new ObjectFactoryException( "Encryption requested not available" );
}
}
// From IPasswordService
@Override
public String decrypt( String encryptedPassword ) throws PasswordServiceException {
try {
Cipher decCipher = Cipher.getInstance( secretKey.getAlgorithm() );
decCipher.init( Cipher.DECRYPT_MODE, secretKey, paramSpec );
byte[] toDecryptBytes = Base64.decodeBase64( encryptedPassword.getBytes() );
byte[] decryptedBytes = decCipher.doFinal( toDecryptBytes );
return new String( decryptedBytes, LocaleHelper.getSystemEncoding() );
} catch ( Exception ex ) {
throw new PasswordServiceException( ex );
}
}
@Override
public String encrypt( String clearPassword ) throws PasswordServiceException {
try {
Cipher encCipher = Cipher.getInstance( secretKey.getAlgorithm() );
encCipher.init( Cipher.ENCRYPT_MODE, secretKey, paramSpec );
byte[] toEncryptBytes = clearPassword.getBytes( LocaleHelper.getSystemEncoding() );
byte[] encBytes = encCipher.doFinal( toEncryptBytes );
byte[] base64Bytes = Base64.encodeBase64( encBytes );
return new String( base64Bytes );
} catch ( Exception ex ) {
throw new PasswordServiceException( ex );
}
}
public static void main( String[] args ) {
CipherEncryptionService service = new CipherEncryptionService();
try {
service.afterPropertiesSet();
if ( args.length != 2 ) {
throw new IllegalArgumentException( "Usage: CipherEncryptionService encrypt|decrypt password" );
}
if ( args[0].equalsIgnoreCase( "encrypt" ) ) {
System.out.println( service.encrypt( args[1] ) );
} else if ( args[0].equalsIgnoreCase( "decrypt" ) ) {
System.out.println( service.decrypt( args[1] ) );
} else {
throw new IllegalArgumentException( "Usage: CipherEncryptionService encrypt|decrypt password" );
}
} catch ( Exception ex ) {
ex.printStackTrace();
}
}
}